Plugin API Reference
Complete reference for the Schemify Plugin SDK (ABI v6). All types live in @import("PluginIF").
Wire Format
Every message uses the same framing:
[u8 tag ] message type
[u16 payload_sz] payload byte count, little-endian
[N bytes ] payload
Strings inside payloads: [u16 len LE][N bytes] (UTF-8, no null terminator)
f32 arrays: [u32 count LE][count × 4 bytes LE]
Descriptor
Every plugin must export schemify_plugin:
pub const Descriptor = extern struct {
abi_version: u32 = ABI_VERSION, // must equal 6
name: [*:0]const u8,
version_str: [*:0]const u8,
process: ProcessFn,
};
export const schemify_plugin: Plugin.Descriptor = .{
.name = "my-plugin",
.version_str = "0.1.0",
.process = schemify_process,
};
ProcessFn
pub const ProcessFn = *const fn (
in_ptr: [*]const u8,
in_len: usize,
out_ptr: [*]u8,
out_cap: usize,
) callconv(.c) usize;
Return bytes written, or maxInt(usize) if output buffer too small (host will retry with doubled buffer).
Reader / InMsg
var r = Plugin.Reader.init(in_ptr[0..in_len]);
while (r.next()) |msg| {
switch (msg) { ... }
}
Lifecycle Messages
| Variant | Payload | Description |
|---|---|---|
.load |
— | Register panels and keybinds here |
.unload |
— | Release resources |
.tick |
dt: f32 |
Per-frame tick; dt = elapsed seconds |
UI Events
| Variant | Payload | Description |
|---|---|---|
.draw_panel |
panel_id: u16 |
Emit UI widgets for this panel |
.button_clicked |
panel_id, widget_id: u32 |
Button was clicked |
.slider_changed |
panel_id, widget_id, val: f32 |
Slider value changed |
.text_changed |
panel_id, widget_id, text: []const u8 |
Text input changed |
.checkbox_changed |
panel_id, widget_id, val: u8 |
Checkbox toggled |
Schematic Events
| Variant | Payload | Description |
|---|---|---|
.schematic_changed |
— | Active schematic modified |
.selection_changed |
instance_idx: i32 |
Selected instance changed; -1 = none |
.instance_data |
idx, name, symbol |
One instance from queryInstances |
.net_data |
idx, name |
One net from queryNets |
Writer Commands
var w = Plugin.Writer.init(out_ptr[0..out_cap]);
// ... write messages ...
return if (w.overflow()) std.math.maxInt(usize) else w.pos;
Panel & Status
w.registerPanel(.{
.id = "waveform",
.title = "Waveform Viewer",
.vim_cmd = "wv",
.layout = .bottom_bar,
.keybind = 'w',
});
w.setStatus("simulation complete");
Logging
w.log(.info, "sim", "starting ngspice");
w.log(.warn, "sim", "convergence issues detected");
w.log(.err, "sim", "ngspice exited with code 1");
Schematic Editing
w.placeDevice("sky130_fd_pr__nfet_01v8", "M1", 100, 200);
w.addWire(100, 200, 100, 300);
w.setInstanceProp(3, "W", "2u");
Queries (async — responses arrive next tick)
w.queryInstances(); // → .schematic_snapshot, .instance_data, .instance_prop
w.queryNets(); // → .schematic_snapshot, .net_data
Persistent State
w.setState("last_file", path);
w.getState("last_file");
// → .state_response next tick
Keybinds
w.registerKeybind('r', 0, "run-simulation");
// → .command { .tag = "run-simulation" } when pressed
UI Widgets
Emit during .draw_panel. id must be unique within one draw call.
w.label("Threshold:", 0);
w.slider(threshold, 0.0, 1.0, 1);
w.button("Run Simulation", 2);
w.separator(3);
w.checkbox(show_labels, "Show net labels", 4);
w.progress(sim_progress, 5);
w.plot("Vout vs Time", time_arr, voltage_arr, 6);
w.image(rgba_data, 256, 256, 7);
// Horizontal layout
w.beginRow(8);
w.label("W:", 9);
w.button("2u", 10);
w.endRow(8);
// Collapsible section
w.collapsibleStart("Advanced", false, 11);
w.slider(gain, 0, 10, 12);
w.collapsibleEnd(11);
PanelLayout
pub const PanelLayout = enum(u8) {
overlay = 0, // floating overlay / modal
left_sidebar = 1, // docked left
right_sidebar = 2, // docked right
bottom_bar = 3, // docked bottom
};
Vfs — Virtual Filesystem
Platform-agnostic FS API. Works identically on native and WASM.
const data = try Plugin.Vfs.readAlloc(alloc, "config.toml");
defer alloc.free(data);
try Plugin.Vfs.writeAll("output/result.json", json_bytes);
try Plugin.Vfs.makePath("my-plugin/cache");
if (!Plugin.Vfs.exists("cache/index.json")) {
try buildIndex(alloc);
}
const listing = try Plugin.Vfs.listDir(alloc, "pdk/sky130A/libs.ref/");
defer listing.deinit(alloc);
for (listing.entries) |name| { ... }
LogLevel
pub const LogLevel = enum(u8) { info = 0, warn = 1, err = 2 };